package com.stars.easyms.rest.handler;

import com.stars.easyms.monitor.handler.EasyMsRequestHandler;
import com.stars.easyms.rest.RestService;
import com.stars.easyms.rest.bean.EasyMsRestContext;
import com.stars.easyms.rest.bean.RestLockInfo;
import com.stars.easyms.rest.bean.RestInfo;
import com.stars.easyms.rest.interceptor.EasyMsRestInterceptor;
import com.stars.easyms.rest.lock.EasyMsRestLock;
import com.stars.easyms.rest.properties.EasyMsRestProperties;
import com.stars.easyms.base.util.ApplicationContextHolder;
import org.springframework.lang.Nullable;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.Validator;
import java.util.Set;

/**
 * <p>className: EasyMsRestRequestHandler</p>
 * <p>description: Rest请求处理类</p>
 *
 * @author guoguifang
 * @version 1.2.1
 * @date 2019/7/11 14:32
 */
@SuppressWarnings("unchecked")
public final class EasyMsRestRequestHandler implements EasyMsRequestHandler {

    private final EasyMsRestMessageHandler easyMsRestMessageHandler;

    private final Validator validator;

    private final EasyMsRestInterceptor easyMsRestInterceptor;

    private final EasyMsRestLock easyMsRestLock;

    public void execute(EasyMsRestContext easyMsRestContext) throws Exception {

        // 获取请求数据
        easyMsRestMessageHandler.parseRequestBody(easyMsRestContext);

        // 执行请求并获取返回值，默认无事务状态运行，若需事务需自行增加事务注解
        RestInfo restInfo = easyMsRestContext.getRestInfo();
        try {
            // 获取restService对象
            RestService restServiceInstance = restInfo.getRestServiceInstance();

            // 报文体数据验证
            validateWithException(easyMsRestContext.getRequestBody());

            // 获取锁信息，如果不为空则默认开启锁，如果加锁失败则返回异常信息，这里使用的是阻塞锁若超过配置的超时时间后会返回超时异常
            // rest分布式锁：用于需要在rest接口层面加锁的场景，例如同一个接口同一个用户同一时间只允许进行一次操作的场景或者其他类似场景
            RestLockInfo restLockInfo = restServiceInstance.getRestLockInfo(restInfo, easyMsRestContext.getRequestBody());
            easyMsRestLock.tryRestLock(restLockInfo);

            // 在处理rest请求前的扩展自定义切面操作
            if (easyMsRestInterceptor != null) {
                easyMsRestInterceptor.beforeRest(easyMsRestContext);
            }

            // 执行请求并对output进行转换
            Object responseBody = restServiceInstance.execute(easyMsRestContext.getRequestBody());

            // 如果处理成功则将responseBody放入rest上下文中
            easyMsRestContext.setResponseBody(responseBody);
            easyMsRestContext.setReturnResponseBody(true);
        } finally {

            // 释放rest锁资源
            easyMsRestLock.releaseRestLock();
        }

        // 在执行完rest接口后的扩展自定义切面操作
        if (easyMsRestInterceptor != null) {
            easyMsRestInterceptor.afterRest(easyMsRestContext);
        }
    }

    /**
     * 按照字段注解校验输入字段
     */
    private <T> void validateWithException(@Nullable T body) {
        if (validator != null && body != null) {
            Set<ConstraintViolation<T>> constraintViolations = validator.validate(body);
            if (!constraintViolations.isEmpty()) {
                throw new ConstraintViolationException(constraintViolations);
            }
        }
    }

    public EasyMsRestRequestHandler(EasyMsRestProperties easyMsRestProperties) {
        this.validator = ApplicationContextHolder.getApplicationContext().getBean(Validator.class);
        this.easyMsRestMessageHandler = new EasyMsRestMessageHandler(easyMsRestProperties);
        this.easyMsRestInterceptor = ApplicationContextHolder.getBean(EasyMsRestInterceptor.class);
        this.easyMsRestLock = new EasyMsRestLock();
    }
}
